[小ネタ]CloudWatch LogsのS3エクスポート機能にて指定した時間範囲単位でエクスポートする
お疲れさまです。とーちです。
CloudWatch Logs には指定したロググループのログを S3 にエクスポートする機能があります。便利な機能なのですが、下記の記事にも記載のある通り、大量のログを一度にエクスポートしようとするとエクスポートに失敗することがあります。
S3 バケットへのエクスポートに失敗する CloudWatch Logs のトラブルシューティング
作成後に失敗したタスクをトラブルシューティングするには、[時間範囲] 設定を確認します。大量のデータを含むログストリームをエクスポートし、長い時間範囲を指定すると、エクスポートタスクが失敗することがあります。その場合、短い時間範囲を指定します。
上記の通り、 大量のデータを一度にエクスポートするのではなく、短い時間範囲を指定 すると S3 へのエクスポートが失敗しにくくなるとのことなので、あるロググループ内の全ログを「指定した時間範囲に区切って」エクスポートする、といった処理をスクリプトで書いてみました。
CloudWatch Logs の S3 エクスポートについて
前提としてお伝えしておきたいのですが、CloudWatch Logs の S3 エクスポート機能はあくまでも スポット(一時的な作業用途) で CloudWatch Logs のログを S3 にコピーしたいというときに使うもので、以下の理由から日常的に(例えばバッチとして)使う用途には不向きだと思います。
- エクスポートタスクは同一アカウント内で、一度に 1 つしか動かせない
- ログ量が多いとエクスポートに失敗することがある
CloudWatch Logs のログを常に S3 にも送りたいという要件の場合は、以下記事のようにサブスクリプションフィルターと Kinesis Data Firehose を併用する構成がオススメです。
作成したスクリプト
想定しているユースケースとしては以下です。
- CloudWatch Logs のログを S3 に手動で退避する(一度限りの作業を想定)
- ロググループ内のログ量が大きいため、大きな時間範囲を指定してエクスポートすると失敗する可能性がある
- でも、一つずつ時間範囲を指定してエクスポートするのは面倒
以下が作成したスクリプトになります。 なお、動作確認は macOS 13.1 にて行っております。
#!/bin/sh S3BucketName=<エクスポート先バケット名を記載> LogGroupName=$1 Interval_sec=$2 Interval_msec="${Interval_sec}000" wait_for_export() { # エクスポートタスクの完了確認間隔。 # デフォルト値10秒 # wait_for_export関数を呼ぶ際に第二引数を指定するとその値を使用 local sleep_time=${2:-10} # エクスポートタスクのジョブステータスがCOMPLETEDまたはFAILEDになるまで続ける while true; do job_status=$(aws logs describe-export-tasks \ --task-id ${1} \ --query "exportTasks[0].status.code" \ --output text) echo ${job_status} if [ "$job_status" == "COMPLETED" ]; then break elif [ "$job_status" == "FAILED" ]; then echo "--- The following export task failed ---" aws logs describe-export-tasks --task-id ${1} break fi sleep ${sleep_time} done } # ロググループ内の最初のイベント時刻を取得 Loggroup_FirstEventTime=$(aws logs describe-log-streams \ --log-group-name "${LogGroupName}" \ --query "min(logStreams[*].firstEventTimestamp)" --output json) # ロググループ内の最後のイベント時刻を取得 Loggroup_LastEventTime=$(aws logs describe-log-streams \ --log-group-name "${LogGroupName}" \ --query "max(logStreams[*].lastEventTimestamp)" --output json) # Interval_msecの単位でエクスポートタスクを作成。 # 最初のイベント時刻から最後のイベント時刻までエクスポートする TimeFrom=$Loggroup_FirstEventTime while [ $TimeFrom -lt $Loggroup_LastEventTime ] do TimeTo=$(($TimeFrom+$Interval_msec)) task_id1=$(aws logs create-export-task \ --task-name "cloudwatch-log-group-export1" \ --log-group-name "${LogGroupName}" \ --from $TimeFrom --to $TimeTo \ --destination "${S3BucketName}" \ --query 'taskId' --output text) wait_for_export ${task_id1} TimeFrom=$(($TimeTo+1)) done
使い方は以下の通りです。
bash -x ./cwlogstos3.sh <エクスポートしたいロググループ名> <エクスポート時の時間範囲を区切る間隔(秒)>
まとめ
以上となります。
この記事が誰かのお役に立てばなによりです。
以上、とーちでした。